#include<stdio.h>
#include<stdlib.h>
#include"semantic.h"
//无优化

// X_:表示X的原结构体定义;
// X:表示X_的指针
typedef struct Operand_ *Operand;
typedef struct InterCode_ *InterCode;
//单条中间代码的数据结构定义为（来源于书上）
struct Operand_ {
    enum {
        FROM_ARG,//Args → Exp COMMA Args| Exp;
        // FROM_ARG用于判断是否为传递给exp的arg(参数)
        // 例如:作为函数参数时数组x,x[0]都会被返回address, 但实际上,x[0]应返回basic
        // 如果是该类型，需要在translate_Exp中将其类型改为VARIABLE
        VARIABLE,//VARIABLE为普通函数参数,需要先查询符号表中是否存在再赋值
        TEMP,//TEMP临时变量,int,且用于初始化Operand
        CONSTANT,//CONSTANT常数，int
        ADDRESS,//&t
        WADDRESS,//*t
        FUNCTION,//FUNCTION函数
        LABEL,//LABEL标号
        RELOP,//RELOP比较
    } kind;
    int u_int;//中间变量之后的序号
    char *u_char;//中间变量名
    Type type;//用于数组变量的Offset查询
};
//将中间代码以双向链表的方式组织起来,便于逆序传入参数
struct InterCode_ {
    enum {
        ILABEL, //定义标号x
        IFUNCTION, //定义函数f
        ASSIGN,//赋值操作,注意立即数
        ADD, SUB, MUL, DIV, //加减乘除操作
        ADDRESS1, //取y的地址赋给x;                       x := &y
        ADDRESS2, //取以y值为地址的内存单元的内容赋给x;     x := *y
        ADDRESS3,//取y值赋给以x值为地址的内存单元;        *x := y
        GOTO, //无条件跳转至标号x
        IF, //if语句
        RETURN, //退出当前函数并返回x值
        DEC, //内存空间申请，大小为4的倍数
        ARG,//传实参x。如果如果是传入地址就&，不是则正常传入
        CALL, //调用函数
        PARAM, //函数参数声明,打印param v+u_int
        READ,//从控制台读取x的值
        WRITE//向控制台打印x的值
    } kind;//中间代码的语句的种类
    union {
        struct {
            Operand op;
        } ulabel;//LABEL,FUNCTION,GOTO,RETURN,ARG,PARAM,READ,WRITE
        struct {
            Operand op1, op2;
        } uassign;//ASSIGN,CALL, ADDRESS1,ADDRESS2,ADDRESS3
        struct {
            Operand result, op1, op2;
        } ubinop;//ADD,SUB,MUL,DIV
        struct {
            Operand x, relop, y, z;
        } uif;//IF
        struct {
            Operand op;
            int size;
        } udec;//DEC
    } u;//中间代码的不同格式
    InterCode before;
    InterCode next;
};
//测试中间代码是否能正常打印到命令行界面
void translate_print_test(InterCode temp);
//将中间代码输出到文件
void translate_print(FILE *f);
// 中间代码生成入口函数
void translate_Program(struct Node *now, char *filename);
// 全局变量、结构体、函数定义
void translate_ExtDef(struct Node *now);
// 函数头的定义
void translate_FunDec(struct Node *now);
// 函数体
void translate_CompSt(struct Node *now);
// 0个或者多个def; 如:int a; float b,c ;int d[10];
void translate_DefList(struct Node *now);
// 0个或者多个stmt,表示多个语句
void translate_StmtList(struct Node *now);
// 变量定义
void translate_Def(struct Node *now);
// 语句
void translate_Stmt(struct Node *now);
//0个或者多个dec,如int a,b,c
void translate_DecList(struct Node *now);
//算数表达式的翻译
void translate_Exp(struct Node *now, Operand place);
//条件表达式的翻译
void translate_Cond(struct Node *now, Operand lt, Operand lf);
//变量定义，如:int a; int a = 5;
void translate_Dec(struct Node *now);
//变量定义，如:int a
void translate_VarDec(struct Node *now, Operand place);
//函数参数的翻译
void translate_Args(struct Node *now, InterCode here);
//类型描述符
void translate_Specifier(struct Node *now);
//结构体
void translate_StructSpecifier(struct Node *now);
//将代码加入中间代码双向链表
void add_to_intercode(InterCode interCode);
//新建一个代码Operand
Operand new_temp();
//新建一个LEBEL符号
Operand new_label();
//计算数组偏移
int get_offset(Type return_type);
//计算全部偏移，即type中的所有内存都要加上
int get_size(Type type);
